package com.superhelper.app.service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.pingplusplus.Pingpp;
import com.pingplusplus.exception.PingppException;
import com.pingplusplus.model.Charge;
import com.superhelper.app.common.Consts;
import com.superhelper.app.domain.BuyOrder;
import com.superhelper.app.domain.PayParam;
import com.superhelper.app.domain.PayResult;
import com.superhelper.app.mapper.PayMapper;

@Service
public class PayService {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * pingpp 管理平台对应的 API key
     */
    @Value("${ping.api.key}")
    public String apiKey;
    /**
     * pingpp 管理平台对应的应用 ID
     */
    @Value("${ping.api.appId}")
    public String appId;
    @Value("${online}")
    private Boolean online;
    @Autowired
    private PayMapper payMapper;

    @Autowired
    private AdminService adminService;

    public PayResult pay(PayParam payParam) {
        if (Pingpp.apiKey == null) {
            Pingpp.apiKey = apiKey;
        }
        Charge charge = null;
        Map<String, Object> chargeMap = new HashMap<String, Object>();
        chargeMap.put("amount", BigDecimal.valueOf(100).multiply(payParam.getMoney()).intValue());
        chargeMap.put("currency", "cny");
        chargeMap.put("subject", payParam.getSubject());
        chargeMap.put("body", payParam.getBody());
        BuyOrder bo = createBuyOrder(payParam);
        chargeMap.put("order_no", bo.getBuyOrderCode());
        chargeMap.put("channel", payParam.getChannel());// "alipay"
        String ip = payParam.getIp();
        if (StringUtils.isBlank(ip) || StringUtils.contains(ip, "0:0:0:0")) {
            ip = "127.0.0.1";
        }
        payParam.setIp(ip);
        chargeMap.put("client_ip", ip);
        Map<String, String> app = new HashMap<String, String>();
        app.put("id", appId);
        chargeMap.put("app", app);
        try {
            // 发起交易请求
            charge = Charge.create(chargeMap);
        } catch (PingppException e) {
            log.error("[pay] error request:{}", payParam, e);
            return null;
        }
        PayResult pr = new PayResult();
        pr.setCharge(charge);
        pr.setBuyOrderCode(bo.getBuyOrderCode());
        pr.setUserId(NumberUtils.toLong(bo.getUid()));
        return pr;
    }

    private BuyOrder createBuyOrder(PayParam pp) {
        BuyOrder bo = new BuyOrder();
        bo.setBuyOrderCode(genDealNo());
        bo.setMoney(pp.getMoney());
        bo.setPayed(BigDecimal.ZERO);
        bo.setIp(pp.getIp());
        bo.setOrderFrom(StringUtils.defaultString(pp.getOrderFrom(), "empty"));
        bo.setOrderName(pp.getSubject());
        bo.setOrderType(pp.getOrderType());
        bo.setOriMoney(pp.getOriMoney() == null ? pp.getMoney() : pp.getOriMoney());
        bo.setDiscMoney(pp.getDiscMoney() == null ? BigDecimal.ZERO : pp.getDiscMoney());
        bo.setState(Consts.OrderState.UNPAY);
        bo.setUserType(pp.getUserType());
        bo.setUid(pp.getUid());
        int result = payMapper.addBuyOrder(bo);
        return result > 0 ? bo : null;
    }

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");

    private static String genDealNo() {
        return sdf.format(new Date()) + RandomStringUtils.randomNumeric(6);
    }

    /**
     * 支付成功的处理
     * 
     * @param deallNo
     * @return
     */
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public boolean paySuccess(String dealNo, String payDealNo, Date payTime) {
        BuyOrder pso = payMapper.getBuyOrderByCode(dealNo);
        if (pso == null) {
            log.error("[paySuccess] not found PaySubOrder dealNo:{}", dealNo);
            return false;
        }
        if (pso.getState() < Consts.OrderState.PAYED) {
            pso.setState(Consts.OrderState.PAYED);
            pso.setStateMsg("支付成功");
            pso.setPayed(pso.getMoney());
            int result = payMapper.updateBuyOrder(pso);
            if (result <= 0) {
                log.error("[paySuccess] update paySubOrder failed {}", pso);
                return false;
            }

            String inviteCode = adminService.createCode("pingpp_alipay", 12);
            adminService.updateUserCode(Long.parseLong(pso.getUid()), inviteCode);
            return true;
        }
        return false;
    }

    /**
     * 查询支付订单
     * 
     * @param deallNo
     * @return
     */
    public BuyOrder queryBuyOrder(String dealNo) {
        return payMapper.getBuyOrderByCode(dealNo);
    }
}
